package com.xwaiy.xwaiyrpc.fault.tolerant;

import com.xwaiy.xwaiyrpc.config.RpcConfig;
import com.xwaiy.xwaiyrpc.fault.retry.RetryStrategy;
import com.xwaiy.xwaiyrpc.fault.retry.RetryStrategyFactory;
import com.xwaiy.xwaiyrpc.loadbalancer.LoadBalancer;
import com.xwaiy.xwaiyrpc.loadbalancer.LoadBalancerFactory;
import com.xwaiy.xwaiyrpc.model.RpcRequest;
import com.xwaiy.xwaiyrpc.model.RpcResponse;
import com.xwaiy.xwaiyrpc.registry.Registry;
import com.xwaiy.xwaiyrpc.registry.RegistryFactory;
import com.xwaiy.xwaiyrpc.RpcApplication;
import com.xwaiy.xwaiyrpc.model.ServiceMetaInfo;
import com.xwaiy.xwaiyrpc.server.tcp.VertxTcpClient;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * 降级到其他服务 - 失败自动恢复
 * @Author Xwaiy
 * @Date 2025/9/3 17:55
 **/
@Slf4j
public class FailBackTolerantStrategy implements TolerantStrategy {

    // 失败请求队列，用于后续重试
    private static final Map<String, RpcRequest> failedRequests = new ConcurrentHashMap<>();
    private static final ScheduledExecutorService retryExecutor = Executors.newSingleThreadScheduledExecutor();

    static {
        // 启动定时任务，每10秒重试一次失败请求
        retryExecutor.scheduleAtFixedRate(FailBackTolerantStrategy::retryFailedRequests, 10, 10, TimeUnit.SECONDS);
    }

    @Override
    public RpcResponse doTolerant(Map<String, Object> context, Exception e) {
        RpcRequest request = (RpcRequest) context.get("request");
        ServiceMetaInfo selectedService = (ServiceMetaInfo) context.get("selectedService");

        if (request != null && selectedService != null) {
            // 将失败请求加入重试队列
            String requestKey = selectedService.getServiceKey() + "_" + System.currentTimeMillis();
            failedRequests.put(requestKey, request);
            log.warn("请求失败，已加入重试队列。服务: {}", selectedService.getServiceKey());
        }

        // 立即返回一个空响应，不阻塞调用方
        return RpcResponse.builder()
                .data(null)
                .msg("请求失败，已加入后台重试队列")
                .exception(e)
                .build();
    }

    private static void retryFailedRequests() {
        if (failedRequests.isEmpty()) {
            return;
        }

        log.info("开始重试 {} 个失败请求", failedRequests.size());

        for (Map.Entry<String, RpcRequest> entry : failedRequests.entrySet()) {
            RpcRequest request = entry.getValue();
            String serviceKey = request.getServiceName() + ":" + request.getVersion();

            try {
                RpcConfig rpcConfig = RpcApplication.getRpcConfig();
                Registry registry = RegistryFactory.getInstance(rpcConfig.getRegistryConfig().getRegistry());

                // 重新发现服务
                List<ServiceMetaInfo> serviceList = registry.serviceDiscovery(serviceKey);
                if (serviceList == null || serviceList.isEmpty()) {
                    log.warn("服务 {} 暂无可用实例，继续等待", serviceKey);
                    continue;
                }

                // 使用负载均衡选择服务实例
                LoadBalancer loadBalancer = LoadBalancerFactory.getInstance(rpcConfig.getLoadBalancer());
                Map<String, Object> params = new HashMap<>();
                params.put("method", request.getMethodName());
                ServiceMetaInfo selectedService = loadBalancer.select(params, serviceList);

                // 使用重试机制进行重试
                RetryStrategy retryStrategy = RetryStrategyFactory.getInstance(rpcConfig.getRetryStrategy());
                RpcResponse response = retryStrategy.doRetry(() ->
                        VertxTcpClient.doRequest(request, selectedService)
                );

                if (response != null) {
                    failedRequests.remove(entry.getKey());
                    log.info("请求重试成功，服务: {}", serviceKey);
                }
            } catch (Exception ex) {
                log.warn("请求重试失败，服务: {}, 错误: {}", serviceKey, ex.getMessage());
            }
        }
    }
}